#coding=UTF-8
import os
import xml.dom.minidom as XmlDocument
import copy

fittingsDict = dict(
    D01='201905170901-cuserss6443076documentsbimbim-library-selenplus-range-enblank-endplus-range-expansion-plug',
    D02='201905170901-plus-range-long-radius-bend',
    D03='201905170901-cuserss6443076documentsbimbim-library-selens-range-enbranchessingle-branch---s-range',
    D04='201905170901-cuserss6443076documentsbimbim-library-selenplus-range-enbranchplus-range-single-branch',
    D05A='Trap-S ranger',
    D05B='Trap-S ranger',
    D06='201905170901-cuserss6443076documentsbimbim-library-selenplus-range-entapersplus-range-reducer',
    D07A='201905170901-88-vented-bend---s-range',
    D07B='201905170901-88-vented-bend---s-range',
    D08='201905170901-cuserss6443076documentsbimbim-library-selens-range-enbends88-long-radius-bend---s-range',
    D09A='Arup-GN-Pipe Fitting-Drain CleanEye',
    D09B='Arup-GN-Pipe Fitting-Drain CleanEye',
    D10='201905170901-access-pipe---s-range',
    D11='201905170901-cuserss6443076documentsbimbim-library-selenplus-range-enblank-endplus-range-blank-end',
    A01='Rectangular elbow',
    A02='Rectangular Mitred Offset - Flanged(1)',
    A03='Rectangular Swept Branch - Flanged',
    A04='Rectangular Shoe Branch - Flanged(1)',
    A05='Rectangular Drop Cheeked Radiussed Twin Bend -Slip Joint',
    A06='M_Rectangular Transition-Angle',
    A07='M_Rectangular Transition-Angle',
    A08='AC-Duct Fittings-Rect Tee')

class PipeNode:
    def __init__(self, uniqueId, type):
        self.uniqueId = uniqueId
        self.type = type
        self.xmlNode = None
        self.xmlNodeOriginal = None
        self.connectorList = []
        self.pipeBaseType = None

class PipeNodes:
    def __init__(self):
        self.pipeNodeAllDict = {}

    #解析data文件结点,存储结点数据和关联关系
    def createPipeNodes(self, doc):
        xEntitys = doc.getElementsByTagName('Entitys')
        xEntityList = xEntitys[0].getElementsByTagName('Entity')
        #遍历Entitys结点,加入pipeNodeAllDict
        for entity in xEntityList:
            uniqueId = entity.attributes['UniqueId'].value
            if '' == uniqueId:
                continue
            type = entity.attributes['type'].value
            if None != self.pipeNodeAllDict.get(uniqueId):
                print('UniqueId(', type, ') has exist:', uniqueId)
                continue
            if 'Duct' == type or 'Pipe' == type:
                pipeNode = PipeNode(uniqueId, type)
                pipeNode.xmlNode = entity
                self.pipeNodeAllDict[uniqueId] = pipeNode
        
        #遍历InputConnector结点,加入pipeNodeAllDict
        xEntityList = xEntitys[0].getElementsByTagName('InputConnector')
        for inputConnector in xEntityList:
            uniqueId = inputConnector.attributes['UniqueId'].value
            if '' == uniqueId:
                continue
            if None != self.pipeNodeAllDict.get(uniqueId):
                print('UniqueId(InputConnector) has exist:', uniqueId)
                continue
            type = 'InputConnector'
            pipeNode = PipeNode(uniqueId, type)
            pipeNode.xmlNode = inputConnector
            self.pipeNodeAllDict[uniqueId] = pipeNode

        #遍历FittingEntity结点,加入pipeNodeAllDict
        xFittings = doc.getElementsByTagName('Fittings')
        xFittingList = xFittings[0].getElementsByTagName('FittingEntity')
        for fittingEntity in xFittingList:
            uniqueId = fittingEntity.attributes['UniqueId'].value
            if '' == uniqueId:
                continue
            if None != self.pipeNodeAllDict.get(uniqueId):
                print('UniqueId(FittingEntity) has exist:', uniqueId)
                continue
            type = 'FittingEntity'
            pipeNode = PipeNode(uniqueId, type)
            pipeNode.xmlNode = fittingEntity
            self.pipeNodeAllDict[uniqueId] = pipeNode

        #重新遍历Entitys,记录原始结点信息
        xEntitys = doc.getElementsByTagName('Entitys')
        xEntityList = xEntitys[0].getElementsByTagName('Entity')
        for entity in xEntityList:
            uniqueId = entity.attributes['UniqueId'].value
            type = entity.attributes['type'].value
            pipeNode = self.pipeNodeAllDict.get(uniqueId)
            if None == pipeNode:
                continue
            if 'AC Point' == type or 'DR Point' == type or 'AC Line' == type or 'DR Line' == type:
                pipeNode.xmlNodeOriginal = entity           

        #遍历InputConnector和FittingEntity,生成连接关系
        for uniqueId,pipeNode in self.pipeNodeAllDict.items():
            if 'InputConnector' == pipeNode.type or 'FittingEntity' == pipeNode.type:
                connectorEntitys = pipeNode.xmlNode.attributes['ConnectorEntitys'].value
                if '' == connectorEntitys:
                    continue
                connectorEntitysList = connectorEntitys.split(';')
                pipeNode.connectorList = connectorEntitysList
                for uniqueIdReverse in pipeNode.connectorList[:]:
                    pipeNodeReverse = self.pipeNodeAllDict.get(uniqueIdReverse)
                    if None == pipeNodeReverse:
                        pipeNode.connectorList.remove(uniqueIdReverse)
                        print('There has a viewbox:', uniqueIdReverse)
                        continue
                    #生成实体结点的连接关系(连接件不需要生成连接关系)
                    if 'InputConnector' != pipeNodeReverse.type and 'FittingEntity' != pipeNodeReverse.type:
                        pipeNodeReverse.connectorList.append(uniqueId)
                        if 'InputConnector' == pipeNode.type:
                            pipeNodeReverse.pipeBaseType = 'Line' + pipeNodeReverse.type
                            pipeNode.pipeBaseType = 'Line' + pipeNodeReverse.type
                        else:
                            pipeNodeReverse.pipeBaseType = pipeNodeReverse.type
                            pipeNode.pipeBaseType = pipeNodeReverse.type
        return

    def print(self):
        for pipeNode in self.pipeNodeAllDict.values():
            print('Node uniqueId:', pipeNode.uniqueId, ' Type:', )
            for uniqueId in pipeNode.connectPipeNodeIdList:
                print('Connect uniqueId:', uniqueId)

class PipeBase():
    def __init__(self, docOrder, pipeNodes):
        self.pipeGroups = {}
        self.docOrder = docOrder
        self.pipeNodes = pipeNodes

    def addPipe(self, node):
        connectorNum = len(node.child)
        if None != node.parent:
            connectorNum += 1
        if 3 <= connectorNum:
            return

        pipeGroupNo = node.treeNo
        pipeGroup = self.pipeGroups.get(pipeGroupNo)
        pipeGroupType = node.pipeBaseType
        if None == pipeGroup:
            pipeGroup = PipeGroup(pipeGroupNo, pipeGroupType)
            self.pipeGroups[pipeGroupNo] = pipeGroup
        else:
            if None != node.pipeBaseType:
                pipeGroup.type = pipeGroupType
        pipeGroup.addPipe(node)

    def sortPipeFlow(self):
        for group in self.pipeGroups.values():
            group.sortPipeFlow(self.pipeNodes)

    def createXmlData(self, trees):
        xPipeBase = self.docOrder.createElement('PipeBase')
        self.docOrder.getElementsByTagName('Root')[0].appendChild(xPipeBase)
        for group in self.pipeGroups.values():
            group.createXmlData(xPipeBase, self.docOrder, self.pipeNodes, trees)
        return

class PipeGroup():
    def __init__(self, pipeGroupNo, type):
        self.pipeGroupNo = pipeGroupNo
        self.type = type
        self.pipeListDic = {}

    def addPipe(self, node):
        if None == node.parent:
            node.pipeListNo = len(self.pipeListDic) + 1
        else:
            parentConnectors = len(node.parent.child)
            if None != node.parent.parent:
                parentConnectors += 1
            if 3 > parentConnectors:
                node.pipeListNo = node.parent.pipeListNo
            else:
                node.pipeListNo = len(self.pipeListDic) + 1

        pList =  self.pipeListDic.get(node.pipeListNo)
        if None != pList:
            pList.addPipe(node)
        else:
            pList = PipeList(node.pipeListNo, self.pipeGroupNo)
            pList.addPipe(node)
            self.pipeListDic[node.pipeListNo] = pList

    def sortPipeFlow(self, pipeNodes, trees):
        for list in self.pipeListDic.values():
            list.sortPipeFlow(self.type, pipeNodes, trees)

        maxSizePipeList = None
        maxSize = 0
        if 'Pipe' == self.type:
            for list in self.pipeListDic.values():
                if list.maxSize > maxSize:
                    maxSizePipeList = list
                    maxSize = list.maxSize
            if None == maxSizePipeList:
                return
            maxSizePipeList.mark = 'E'
            for list in self.pipeListDic.values():
                if '' != list.mark:
                    continue
                startPipe = list.pipes[0]
                endPipe = list.pipes[len(list.pipes)-1]
                #如果是夹在中间的列则mark为空
                if None != trees.nodeDict[startPipe.uniqueId].parent and 0 != len(trees.nodeDict[startPipe.uniqueId].child) and None != trees.nodeDict[endPipe.uniqueId].parent and 0 != len(trees.nodeDict[endPipe.uniqueId].child):
                    continue
                list.mark = 'S'
        elif 'Duct' == self.type:
            for list in self.pipeListDic.values():
                if list.maxSize > maxSize:
                    maxSizePipeList = list
                    maxSize = list.maxSize
            if None == maxSizePipeList:
                return
            maxSizePipeList.mark = 'S'
            for list in self.pipeListDic.values():
                if '' != list.mark:
                    continue
                startPipe = list.pipes[0]
                endPipe = list.pipes[len(list.pipes)-1]
                #如果是夹在中间的列则mark为空
                if None != trees.nodeDict[startPipe.uniqueId].parent and 0 != len(trees.nodeDict[startPipe.uniqueId].child) and None != trees.nodeDict[endPipe.uniqueId].parent and 0 != len(trees.nodeDict[endPipe.uniqueId].child):
                    continue
                list.mark = 'E'

    def createXmlData(self, xPipeBase, docOrder, pipeNodes, trees):
        if None == self.type:
            return

        self.sortPipeFlow(pipeNodes, trees)

        xPipeGroup  = docOrder.createElement('PipeGroup')
        xPipeGroup.attributes['PipeGroupNo'] = str(self.pipeGroupNo)
        xPipeGroup.attributes['type'] = str(self.type)
        xPipeBase.appendChild(xPipeGroup)

        for list in self.pipeListDic.values():
            list.createXmlData(xPipeGroup, pipeNodes, docOrder)

class PipeList():
    def __init__(self, pipeListNo, pipeGroupNo):
        self.pipeGroupNo = pipeGroupNo
        self.pipeListNo = pipeListNo
        self.pipes = []
        self.maxSize = 0
        self.mark = ''

    def addPipe(self, node):
        pipe = Pipe(node.uniqueId, node.type, self.pipeGroupNo, self.pipeListNo)
        self.pipes.append(pipe)

    def sortPipeFlow(self, groupType, pipeNodes, trees):
        if 'LineDuct' == groupType or 'LinePipe' == groupType:
            pipe = self.pipes[0]
            hasStartPoint = False
            if 'Pipe' == pipe.type or 'Duct' == pipe.type:
                parent = trees.nodeDict[pipe.uniqueId].parent
                if None != parent:
                    startPointId = parent.uniqueId
                    hasStartPoint = True
                else:   #没有起点,则以下一个连接件作为参考
                    entity = pipeNodes.pipeNodeAllDict.get(pipe.uniqueId).xmlNode
                    entityStartPoint = entity.getElementsByTagName('LocationEnt')[0].attributes['StartPoint'].value.split(',')
                    entityEndPoint = entity.getElementsByTagName('LocationEnt')[0].attributes['EndPoint'].value.split(',')

                    endPointXmlNodeOriginal = pipeNodes.pipeNodeAllDict.get(self.pipes[1].uniqueId).xmlNodeOriginal
                    endPoint = endPointXmlNodeOriginal.getElementsByTagName('LocationEnt')[0].attributes['Point'].value.split(',')
                    startDistance = abs(float(endPoint[0]) - float(entityStartPoint[0])) + abs(float(endPoint[1]) - float(entityStartPoint[1])) + abs(float(endPoint[2]) - float(entityStartPoint[2]))
                    endDistance = abs(float(endPoint[0]) - float(entityEndPoint[0])) + abs(float(endPoint[1]) - float(entityEndPoint[1])) + abs(float(endPoint[2]) - float(entityEndPoint[2]))

                    if startDistance <= endDistance:
                        startPoint = entityEndPoint
                    else:
                        startPoint = entityStartPoint
            else:
                startPointId = pipe.uniqueId
                hasStartPoint = True

            if True == hasStartPoint:
                startPointXmlNodeOriginal = pipeNodes.pipeNodeAllDict.get(startPointId).xmlNodeOriginal
                if None == startPointXmlNodeOriginal:
                    print("xml node(line) original not exist:", startPointId)
                    return

                startPoint = startPointXmlNodeOriginal.getElementsByTagName('LocationEnt')[0].attributes['Point'].value.split(',')
        elif 'Duct' == groupType or 'Pipe' == groupType:
            pipe = self.pipes[0]
            if 1 == len(self.pipes):
                pipeNode = pipeNodes.pipeNodeAllDict.get(pipe.uniqueId)
                if 'Duct' == pipeNode.type or 'Pipe' == pipeNode.type:
                    entityStartPoint = pipeNode.xmlNode.getElementsByTagName('LocationEnt')[0].attributes['StartPoint'].value.split(',')
                    entityEndPoint = pipeNode.xmlNode.getElementsByTagName('LocationEnt')[0].attributes['EndPoint'].value.split(',')
                    pipe.startPoint = entityStartPoint
                    pipe.endPoint = entityEndPoint

                    if 'Duct' == groupType:
                        entity = pipeNodes.pipeNodeAllDict.get(pipeNode.uniqueId).xmlNode
                        if 'Duct' != entity.attributes['type'].value:
                            print('groupType is Duct, but entity type is:', entity.attributes['type'].value, 'uniqueId:', pipeNode.uniqueId)
                            return
                        width = entity.getElementsByTagName('DuctType')[0].attributes['Length1'].value
                        height = entity.getElementsByTagName('DuctType')[0].attributes['Length2'].value
                        self.maxSize = float(width) * float(height)
                    elif 'Pipe' == groupType:
                        entity = pipeNodes.pipeNodeAllDict.get(pipeNode.uniqueId).xmlNode
                        width = float(entity.getElementsByTagName('Radius')[0].attributes['value'].value) * 2
                        height = float(entity.getElementsByTagName('Radius')[0].attributes['value'].value) * 2
                        self.maxSize = width * height

                    return
            
            hasStartPoint = False
            if 'Pipe' == pipe.type or 'Duct' == pipe.type:
                parent = trees.nodeDict[pipe.uniqueId].parent
                if None != parent:
                    startPointId = parent.uniqueId
                    hasStartPoint = True
                else:   #没有起点,则以下一个连接件作为参考
                    entity = pipeNodes.pipeNodeAllDict.get(pipe.uniqueId).xmlNode
                    entityStartPoint = entity.getElementsByTagName('LocationEnt')[0].attributes['StartPoint'].value.split(',')
                    entityEndPoint = entity.getElementsByTagName('LocationEnt')[0].attributes['EndPoint'].value.split(',')

                    endPointXmlNode = pipeNodes.pipeNodeAllDict.get(self.pipes[1].uniqueId).xmlNode
                    endPoint = endPointXmlNode.attributes['Point'].value.split(',')
                    startDistance = abs(float(endPoint[0]) - float(entityStartPoint[0])) + abs(float(endPoint[1]) - float(entityStartPoint[1])) + abs(float(endPoint[2]) - float(entityStartPoint[2]))
                    endDistance = abs(float(endPoint[0]) - float(entityEndPoint[0])) + abs(float(endPoint[1]) - float(entityEndPoint[1])) + abs(float(endPoint[2]) - float(entityEndPoint[2]))

                    if startDistance <= endDistance:
                        startPoint = entityEndPoint
                    else:
                        startPoint = entityStartPoint
            else:
                startPointId = pipe.uniqueId
                hasStartPoint = True

            if True == hasStartPoint:
                startPointXmlNode = pipeNodes.pipeNodeAllDict.get(startPointId).xmlNode
                if None == startPointXmlNode:
                    print("xml node(entity) not exist:", startPointId)
                    return

                startPoint = startPointXmlNode.attributes['Point'].value.split(',')
        else:
            print('unknown group type:', groupType, 'pipeListNo:', self.pipeListNo, 'pipeListNo:', self.pipeListNo)
            return

        lastEntityEndPoint = startPoint

        for pipe in self.pipes:
            if 'Pipe' == pipe.type or 'Duct' == pipe.type:
                entity = pipeNodes.pipeNodeAllDict.get(pipe.uniqueId).xmlNode
                entityStartPoint = entity.getElementsByTagName('LocationEnt')[0].attributes['StartPoint'].value.split(',')
                entityEndPoint = entity.getElementsByTagName('LocationEnt')[0].attributes['EndPoint'].value.split(',')

                startDistance = abs(float(lastEntityEndPoint[0]) - float(entityStartPoint[0])) + abs(float(lastEntityEndPoint[1]) - float(entityStartPoint[1])) + abs(float(lastEntityEndPoint[2]) - float(entityStartPoint[2]))
                endDistance = abs(float(lastEntityEndPoint[0]) - float(entityEndPoint[0])) + abs(float(lastEntityEndPoint[1]) - float(entityEndPoint[1])) + abs(float(lastEntityEndPoint[2]) - float(entityEndPoint[2]))

                if startDistance <= endDistance:
                    pipe.startPoint = entityStartPoint
                    pipe.endPoint = entityEndPoint
                else:
                    pipe.startPoint = entityEndPoint
                    pipe.endPoint = entityStartPoint

                lastEntityEndPoint = pipe.endPoint

        #风管按照从粗到细的原则排序，水管根据Z值优先从高到低，同等Z值从细到粗排序
        pipeCount = len(self.pipes)
        i = 0
        firstPipe = None
        while i < pipeCount:
            if 'Pipe' == self.pipes[i].type or 'Duct' == self.pipes[i].type:
                firstPipe = self.pipes[i]
                break
            i = i + 1

        i = pipeCount - 1
        lastPipe = None
        while i >= 0:
            if 'Pipe' == self.pipes[i].type or 'Duct' == self.pipes[i].type:
                lastPipe = self.pipes[i]
                break
            i = i - 1

        if firstPipe == lastPipe:
            if None != firstPipe:
                if 'Duct' == groupType:
                    entity = pipeNodes.pipeNodeAllDict.get(firstPipe.uniqueId).xmlNode
                    if 'Duct' != entity.attributes['type'].value:
                        print('groupType is Duct, but entity type is:', entity.attributes['type'].value, 'uniqueId:', firstPipe.uniqueId)
                        return
                    width = entity.getElementsByTagName('DuctType')[0].attributes['Length1'].value
                    height = entity.getElementsByTagName('DuctType')[0].attributes['Length2'].value
                    self.maxSize = float(width) * float(height)
                elif 'Pipe' == groupType:
                    entity = pipeNodes.pipeNodeAllDict.get(firstPipe.uniqueId).xmlNode
                    if 'Pipe' != entity.attributes['type'].value:
                        print('groupType is Pipe, but entity type is:', entity.attributes['type'].value, 'uniqueId:', firstPipe.uniqueId)
                        return
                    width = float(entity.getElementsByTagName('Radius')[0].attributes['value'].value) * 2
                    height = float(entity.getElementsByTagName('Radius')[0].attributes['value'].value) * 2
                    self.maxSize = width * height
            return

        reorder = False
        if 'Duct' == groupType:
            entity = pipeNodes.pipeNodeAllDict.get(firstPipe.uniqueId).xmlNode
            if 'Duct' != entity.attributes['type'].value:
                print('groupType is Duct, but entity type is:', entity.attributes['type'].value, 'uniqueId:', firstPipe.uniqueId)
                return
            width = entity.getElementsByTagName('DuctType')[0].attributes['Length1'].value
            height = entity.getElementsByTagName('DuctType')[0].attributes['Length2'].value
            firstPipeSize = float(width) * float(height)

            entity = pipeNodes.pipeNodeAllDict.get(lastPipe.uniqueId).xmlNode
            width = entity.getElementsByTagName('DuctType')[0].attributes['Length1'].value
            height = entity.getElementsByTagName('DuctType')[0].attributes['Length2'].value
            lastPipeSize = float(width) * float(height)

            #风管排序从粗到细
            if firstPipeSize < lastPipeSize:
                reorder = True
                self.maxSize = lastPipeSize
            else:
                self.maxSize = firstPipeSize
        elif 'Pipe' == groupType:
            firstPipeStartPointZ = firstPipe.startPoint[2]
            lastPipeEndPointZ = lastPipe.endPoint[2]
            if firstPipeStartPointZ < lastPipeEndPointZ:
                reorder = True
            elif firstPipeStartPointZ == lastPipeEndPointZ:
                entity = pipeNodes.pipeNodeAllDict.get(firstPipe.uniqueId).xmlNode
                width = float(entity.getElementsByTagName('Radius')[0].attributes['value'].value) * 2
                height = float(entity.getElementsByTagName('Radius')[0].attributes['value'].value) * 2
                firstPipeSize = width * height

                entity = pipeNodes.pipeNodeAllDict.get(lastPipe.uniqueId).xmlNode
                width = float(entity.getElementsByTagName('Radius')[0].attributes['value'].value) * 2
                height = float(entity.getElementsByTagName('Radius')[0].attributes['value'].value) * 2
                lastPipeSize = width * height

                #水管排序从细到粗
                if firstPipeSize > lastPipeSize:
                    reorder = True
                    self.maxSize = firstPipeSize
                else:
                    self.maxSize = lastPipeSize
            if 0 == self.maxSize:
                entity = pipeNodes.pipeNodeAllDict.get(firstPipe.uniqueId).xmlNode
                if 'Pipe' != entity.attributes['type'].value:
                    print('groupType is Pipe, but entity type is:', entity.attributes['type'].value, 'uniqueId:', firstPipe.uniqueId)
                    return
                width = float(entity.getElementsByTagName('Radius')[0].attributes['value'].value) * 2
                height = float(entity.getElementsByTagName('Radius')[0].attributes['value'].value) * 2
                firstPipeSize = width * height

                entity = pipeNodes.pipeNodeAllDict.get(lastPipe.uniqueId).xmlNode
                width = float(entity.getElementsByTagName('Radius')[0].attributes['value'].value) * 2
                height = float(entity.getElementsByTagName('Radius')[0].attributes['value'].value) * 2
                lastPipeSize = width * height

                if firstPipeSize > lastPipeSize:
                    self.maxSize = firstPipeSize
                else:
                    self.maxSize = lastPipeSize
        elif 'LinePipe' == groupType or 'LineDuct' == groupType:
            return
        else:
            print('Type error:', groupType)
            return

        if True != reorder:
            return

        self.pipes.reverse()

        for pipe in self.pipes:
            if 'Pipe' == pipe.type or 'Duct' == pipe.type:
                tmp = pipe.startPoint
                pipe.startPoint = pipe.endPoint
                pipe.endPoint = tmp

    def createXmlData(self, xPipeGroup, pipeNodes, docOrder):
        for pipe in self.pipes:
            if 'InputConnector' == pipe.type or 'FittingEntity' == pipe.type:
                xmlNodeOriginal = pipeNodes.pipeNodeAllDict.get(pipe.uniqueId).xmlNodeOriginal
                if None != xmlNodeOriginal:
                    mark = xmlNodeOriginal.getElementsByTagName('Params')[0].attributes['Mark'].value
                    if '' != mark:
                        self.mark = mark
                        break

        entity = None
        for pipe in self.pipes:
            if 'Pipe' == pipe.type or 'Duct' == pipe.type:
                entity = pipeNodes.pipeNodeAllDict.get(pipe.uniqueId).xmlNode
                break
        if None == entity:
            print('pipeGroupNo:', self.pipeGroupNo, 'pipeListNo:', self.pipeListNo, ' has no entity')
            for pipe in self.pipes:
                print('uniqueId:', pipe.uniqueId)
            return
        xPipeList  = docOrder.createElement('PipeList')
        xPipeList.attributes['PipeListNo'] = str(self.pipeListNo)
        xPipeList.attributes['PrevListNo'] = str(self.pipeListNo - 1)
        xPipeList.attributes['TeeId_Next'] = ''
        xPipeList.attributes['FamilyName'] = entity.getElementsByTagName('FamilyName')[0].attributes['value'].value
        xPipeList.attributes['SymbolName'] = entity.getElementsByTagName('SymbolName')[0].attributes['value'].value
        xPipeList.attributes['SystemClassfy'] = entity.getElementsByTagName('SystemClassfy')[0].attributes['value'].value
        xPipeList.attributes['SystemType'] = entity.getElementsByTagName('SystemType')[0].attributes['value'].value
        xPipeList.attributes['InsulationTypeName'] = entity.getElementsByTagName('InsulationType')[0].attributes['Name'].value
        xPipeList.attributes['InsulationTypeThickness'] = entity.getElementsByTagName('InsulationType')[0].attributes['Thickness'].value
        xPipeList.attributes['HorizonOffset'] = entity.getElementsByTagName('HorizonOffset')[0].attributes['value'].value
        xPipeList.attributes['VerticalOffset'] = entity.getElementsByTagName('VerticalOffset')[0].attributes['value'].value
        xPipeList.attributes['Color'] = entity.getElementsByTagName('Color')[0].attributes['value'].value
        if 'Duct' == pipe.type:
            xPipeList.attributes['DuctType'] = entity.getElementsByTagName('DuctType')[0].attributes['value'].value
        else:
            xPipeList.attributes['DuctType'] = ''
        xPipeList.attributes['DuctType'] = ''
        xPipeList.attributes['Mark'] = self.mark
        xPipeGroup.appendChild(xPipeList)

        #对点线管道根据mark属性排序
        lastPipe = self.pipes[-1]
        if 'InputConnector' == lastPipe.type:
            mark = pipeNodes.pipeNodeAllDict.get(lastPipe.uniqueId).xmlNodeOriginal.getElementsByTagName('Params')[0].attributes['Mark'].value
            if 'S' == mark:
                self.pipes.reverse()

        for pipe in self.pipes:
            pipe.createXmlData(xPipeList, docOrder, pipeNodes)
        return

class Pipe():
    def __init__(self, uniqueId, type, pipeGroupNo, pipeListNo):
        self.uniqueId = uniqueId
        self.type = type
        self.startPoint = []
        self.endPoint = []
        self.pipeGroupNo = pipeGroupNo
        self.pipeListNo = pipeListNo

    def createXmlData(self, xPipeList, docOrder, pipeNodes):
        if 'FittingEntity' == self.type:
            return
        if 'InputConnector' == self.type:
            point  = docOrder.createElement('Point')
            entity = pipeNodes.pipeNodeAllDict.get(self.uniqueId).xmlNode
            point.attributes['UniqueId'] = entity.attributes['UniqueId'].value
            point.attributes['FamilyName'] = entity.attributes['FamilyName'].value
            point.attributes['SymbolName'] = entity.attributes['SymbolName'].value
            point.attributes['ConnectorEntitys'] = entity.attributes['ConnectorEntitys'].value
            try:
                point.attributes['Fittings'] = entity.attributes['Fittings'].value
                point.attributes['FamilyName'] = fittingsDict[entity.attributes['Fittings'].value]
                point.attributes['SymbolName'] = 'Standard'
            except:
                point.attributes['FamilyName'] = 'Default'
                point.attributes['SymbolName'] = 'Default'
            xPipeList.appendChild(point)
            return
        pipe  = docOrder.createElement('Pipe')
        entity = pipeNodes.pipeNodeAllDict.get(self.uniqueId).xmlNode
        if None != entity:
            pipe.attributes['UniqueId'] = entity.attributes['UniqueId'].value
            pipe.attributes['StartPoint'] = ','.join(self.startPoint)
            pipe.attributes['EndPoint'] = ','.join(self.endPoint)

            if 'Duct' == self.type:
                pipe.attributes['Width'] = entity.getElementsByTagName('DuctType')[0].attributes['Length1'].value
                pipe.attributes['Height'] = entity.getElementsByTagName('DuctType')[0].attributes['Length2'].value
                pipe.attributes['Transform'] = entity.getElementsByTagName('Transform')[0].attributes['value'].value
            elif 'Pipe' == self.type:
                pipe.attributes['Width'] = str(float(entity.getElementsByTagName('Radius')[0].attributes['value'].value) * 2)
                pipe.attributes['Height'] = str(float(entity.getElementsByTagName('Radius')[0].attributes['value'].value) * 2)
                pipe.attributes['Transform'] = ''
        xPipeList.appendChild(pipe)
        return

class Node():
    def __init__(self, uniqueId, type, pipeBaseType):
        self.uniqueId = uniqueId
        self.type = type
        self.parent = None
        self.child = []
        self.treeNo = 0
        self.pipeListNo = 0
        self.pipeBaseType = pipeBaseType
        return

class Tree():
    def __init__(self):
        self.nodeDict = {}
        self.root = None
        self.pipeBase = None

    def travel(self, node):
        if None == node:
            return
        self.pipeBase.addPipe(node)
        for c in node.child:
            self.travel(c)
        return

class Trees():
    def __init__(self):
        self.nodeDict = {}
        self.trees = []

    def findPipeNodeType(self, node):
        if None == node:
            return
        if None != node.pipeBaseType:
            return node.pipeBaseType
        for c in node.child:
            pipeBaseType = self.findPipeNodeType(c)
            if None != pipeBaseType:
                return pipeBaseType
    
    def createNodeTreeNo(self, node, treeNo, pipeBaseType):
        if None == node:
            return

        node.treeNo = treeNo
        if None == node.pipeBaseType:
            node.pipeBaseType = pipeBaseType

        for c in node.child:
            self.createNodeTreeNo(c, treeNo, pipeBaseType)
        return

    def changeRoot(self, newRoot):
        curNode = newRoot
        lastNode = None
        while None != curNode:
            parent = curNode.parent

            curNode.parent = lastNode
            if None != lastNode:
                curNode.child.remove(lastNode)
            if None != parent:
                curNode.child.append(parent)

            lastNode = curNode
            curNode = parent

    def findValidRoot(self, root):
        if None == root:
            return None

        pipes = 0
        if None != root.parent:
            pipes += 1
        pipes += len(root.child)
        if 2 != pipes:
            return root
        for c in root.child:
            return self.findValidRoot(c)

    def createTrees(self, pipeNodes, pipeBase):
        for uniqueId,pipeNode in pipeNodes.pipeNodeAllDict.items():
            if 'InputConnector' != pipeNode.type and 'FittingEntity' != pipeNode.type:
                continue
            nodeConnector = self.nodeDict.get(uniqueId)
            if None == nodeConnector:
                nodeConnector = Node(uniqueId, pipeNode.type, pipeNode.pipeBaseType)
                self.nodeDict[uniqueId] = nodeConnector

            for entity in pipeNode.connectorList:
                nodeConnectorEntity = self.nodeDict.get(entity)
                #如果nodeConnectorEntity不在树中，则将其作为当前结点的子结点
                if None == nodeConnectorEntity:
                    type = pipeNodes.pipeNodeAllDict[entity].type
                    pipeBaseType = pipeNodes.pipeNodeAllDict[entity].pipeBaseType
                    nodeConnectorEntity = Node(entity, type, pipeBaseType)
                    nodeConnectorEntity.parent = nodeConnector;
                    nodeConnector.child.append(nodeConnectorEntity)
                    self.nodeDict[entity] = nodeConnectorEntity
                else:
                    #判断nodeConnectorEntity是否和当前结点已经是父子关系
                    if nodeConnector == nodeConnectorEntity.parent or nodeConnectorEntity ==  nodeConnector.parent:
                        continue
                    
                    #如果nodeConnectorEntity无父结点，由当前结点为父结点
                    if None == nodeConnectorEntity.parent:
                        nodeConnectorEntity.parent = nodeConnector
                        nodeConnector.child.append(nodeConnectorEntity)
                    elif None == nodeConnector.parent:  #如果当前结点无父结点，则nodeConnectorEntity为父结点
                        nodeConnector.parent = nodeConnectorEntity
                        nodeConnectorEntity.child.append(nodeConnector)
                    else:   #如果当前当前结点和nodeConnectorEntity都已经有父结点，则什么都不做
                        root1 = nodeConnector
                        while None != root1.parent:
                            root1 = root1.parent
                        root2 = nodeConnectorEntity
                        while None != root2.parent:
                            root2 = root2.parent
                        if root1 != root2:
                            self.changeRoot(nodeConnector)
                            nodeConnector.parent = nodeConnectorEntity
                            nodeConnectorEntity.child.append(nodeConnector)
                        else:
                            print('There has a cycle:', uniqueId, ':', entity)

        #对没有连接关系的管道进行处理
        for uniqueId,pipeNode in pipeNodes.pipeNodeAllDict.items():
            if 'Pipe' != pipeNode.type and 'Duct' != pipeNode.type:
                continue

            node = self.nodeDict.get(uniqueId)
            if None != node:
                continue

            #没有连接关系的管道pipeBaseType与type相同
            pipeNode.pipeBaseType = pipeNode.type
            node = Node(uniqueId, pipeNode.type, pipeNode.pipeBaseType)
            self.nodeDict[uniqueId] = node

        treeNo = 0
        hasNode = True
        while hasNode:
            treeNo += 1
            hasNode = False
            for uniqueId,node in self.nodeDict.items():
                if 0 == node.treeNo:
                    root = node
                    while None != root.parent:
                        root = root.parent
                    #如果根结点是二通,则将要结点设为一通或者多通
                    if 2 == len(root.child):
                        print('Change tree root(old):', root.uniqueId)
                        root = self.findValidRoot(root)
                        if None != root:
                            self.changeRoot(root)
                            print('Change tree root(new):', root.uniqueId)
                        else:
                            print('Node has no root:', root.uniqueId)
                            continue
                    pipeBaseType = self.findPipeNodeType(root)
                    self.createNodeTreeNo(root, treeNo, pipeBaseType)
                    tree = Tree()
                    tree.root = root;
                    tree.nodeDict = self.nodeDict
                    tree.pipeBase = pipeBase
                    self.trees.append(tree)
                    hasNode = True
                    break;

        return

    def travel(self):
        for tree in self.trees:
            tree.travel(tree.root)
        return

def createTee(docOrder, pipeNodes, trees, pipeBase):
    xTee = docOrder.createElement('Tee')
    docOrder.getElementsByTagName('Root')[0].appendChild(xTee)
    for uniqueid,pipeNode in pipeNodes.pipeNodeAllDict.items():
        if 'InputConnector' != pipeNode.type and 'FittingEntity' != pipeNode.type:
            continue
        node = trees.nodeDict[uniqueid]
        connectors = len(node.child)

        lists = ''
        if None != node.parent:
            connectors += 1
            lists = str(node.parent.treeNo)
        if 3 <= connectors:
            connector = docOrder.createElement('Connector')
            connector.attributes['Group'] = str(trees.nodeDict[uniqueid].treeNo)
            connector.attributes['PipeGroupType'] = trees.nodeDict[uniqueid].pipeBaseType
            connector.attributes['UniqueId'] = uniqueid
            lists = ''
            startList = 0;
            if None != node.parent:
                lists = str(node.parent.pipeListNo)
                print("pipeGroups:", len(pipeBase.pipeGroups))
                print("node.parent.treeNo:", node.parent.treeNo)
                print("pipeBase.pipeGroups[node.parent.treeNo].pipeListDic:", len(pipeBase.pipeGroups[node.parent.treeNo].pipeListDic))
                print("node.parent.pipeListNo:", node.parent.pipeListNo)
                if None != pipeBase.pipeGroups.get(node.parent.treeNo) and None != pipeBase.pipeGroups[node.parent.treeNo].pipeListDic.get(node.parent.pipeListNo):
                    if 'S' == pipeBase.pipeGroups[node.parent.treeNo].pipeListDic[node.parent.pipeListNo].mark:
                        startList += 1
            for c in node.child:
                if '' != lists:
                    lists += ';' + str(c.pipeListNo)
                else:
                    lists = str(c.pipeListNo)
                if c.pipeListNo in pipeBase.pipeGroups[c.treeNo].pipeListDic.keys() and 'S' == pipeBase.pipeGroups[c.treeNo].pipeListDic[c.pipeListNo].mark:
                    startList += 1
                else:
                    print('treeNo:' + str(c.treeNo) + " has no pipe ListNo:" + str(c.pipeListNo))

            connector.attributes['type'] = ''
            if 0 == startList:
                connector.attributes['type'] = 'zero'
            elif 1 == startList:
                connector.attributes['type'] = 'single'
            elif 2 == startList:
                connector.attributes['type'] = 'double'
            connector.attributes['Lists'] = lists
            connector.attributes['ConnectorEntitys'] = pipeNode.xmlNode.attributes['ConnectorEntitys'].value
            connector.attributes['FamilyName'] = pipeNode.xmlNode.attributes['FamilyName'].value
            connector.attributes['SymbolName'] = pipeNode.xmlNode.attributes['SymbolName'].value
            try:
                connector.attributes['Fittings'] = pipeNode.xmlNode.attributes['Fittings'].value
                connector.attributes['FamilyName'] = fittingsDict[pipeNode.xmlNode.attributes['Fittings'].value]
                connector.attributes['SymbolName'] = 'Standard'
            except:
                connector.attributes['FamilyName'] = 'Default'
                connector.attributes['SymbolName'] = 'Default'
            #if None != pipeNode.xmlNodeOriginal:
                #connector.attributes['FamilyName'] = pipeNode.xmlNodeOriginal.getElementsByTagName('FamilyName')[0].attributes['value'].value
                #connector.attributes['SymbolName'] = pipeNode.xmlNodeOriginal.getElementsByTagName('SymbolName')[0].attributes['value'].value
            #else:
                #print('Tee has no entity info:', pipeNode.uniqueId)

            if 'Pipe' == trees.nodeDict[uniqueid].pipeBaseType and 'FittingEntity' == pipeNode.type:
                connectorEntitys = []

                parent = node.parent
                while None != parent:
                    if 'Pipe' == parent.type:
                        connectorEntitys.append(parent.uniqueId)
                        break
                    connectors = 0
                    if None != node.parent:
                        connectors += 1
                    connectors += len(parent.child)
                    if 3 <= connectors:
                        break
                    parent = parent.parent
                
                for child in node.child:
                    childNode = child
                    while None != childNode:
                        if 'Pipe' == childNode.type:
                            connectorEntitys.append(childNode.uniqueId)
                            break
                        if 1 != len(childNode.child):
                            break
                        childNode = childNode.child[0]

                connector.attributes['ConnectorEntitys'] = ';'.join(connectorEntitys)

            xTee.appendChild(connector)

#将data文件排序,生成order文件
def revitData2Order(dataFile, orderFile):
    docData = XmlDocument.parse(dataFile)
    docOrder = copy.copy(docData)
    pipeNodes = PipeNodes()
    pipeNodes.createPipeNodes(docData)

    pipeBase = PipeBase(docOrder, pipeNodes)

    trees = Trees()
    trees.createTrees(pipeNodes, pipeBase)
    print('trees num:', len(trees.trees))
    trees.travel()

    pipeBase.createXmlData(trees)

    createTee(docOrder, pipeNodes, trees, pipeBase)

    with open(orderFile, 'wb') as fp:
        fp.write(docOrder.toxml(encoding='utf-8'))

#合并data文件
def mergeDataFile(dataFileDir):
    dataFiles = []

    fileId = 1
    while fileId <= 3:
        dataFile = os.path.join(dataFileDir, 'revit_data_' + str(fileId) + '.xml')
        if True == os.path.exists(dataFile):
            dataFiles.append(dataFile)
        fileId = fileId + 1

    if 0 == len(dataFiles):
        return

    docDataResult = None
    for dataFile in dataFiles:
        print(dataFile)
        docData = XmlDocument.parse(dataFile)
        if None == docDataResult:
            docDataResult = copy.copy(docData)
            continue

        xEntitys = docData.getElementsByTagName('Entitys')
        xEntityList = xEntitys[0].getElementsByTagName('Entity')
        #遍历Entitys结点,加入docDataResult
        for entity in xEntityList:
            print(dataFile + ":" + entity.attributes['UniqueId'].value)
            docDataResult.getElementsByTagName('Entitys')[0].appendChild(entity)

        xRoutingPreferences = docData.getElementsByTagName('RoutingPreferences')
        xPipeTypeList = xRoutingPreferences[0].getElementsByTagName('PipeType')
        #遍历PipeType结点,加入docDataResult
        for pipeType in xPipeTypeList:
            docDataResult.getElementsByTagName('RoutingPreferences')[0].appendChild(pipeType)

        xFittings = docData.getElementsByTagName('Fittings')
        xFittingEntityList = xFittings[0].getElementsByTagName('FittingEntity')
        #遍历Fittings结点,加入docDataResult
        for fittingEntity in xFittingEntityList:
            print(dataFile + ":" + fittingEntity.attributes['UniqueId'].value)
            docDataResult.getElementsByTagName('Fittings')[0].appendChild(fittingEntity)

    resultFile = os.path.join(dataFileDir, 'revit_data.xml')
    with open(resultFile, 'wb') as fp:
        fp.write(docDataResult.toxml(encoding='utf-8'))


if __name__ == '__main__':
    dataFile = 'revit_data.xml'
    orderFile = 'revit_order.xml'

    revitData2Order(dataFile, orderFile)


# if __name__ == '__main__':
#     dataFileDir = r'C:\Users\Administrator\Desktop\94'
#     mergeDataFile(dataFileDir)

#     dataFile = dataFileDir + r'\revit_data.xml'
#     orderFile = dataFileDir + r'\revit_order.xml'

#     revitData2Order(dataFile, orderFile)